home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Shareware Grab Bag
/
Shareware Grab Bag.iso
/
001
/
pibt3sp3.arc
/
RECEIVEX.PAS
< prev
next >
Wrap
Pascal/Delphi Source File
|
1985-10-03
|
51KB
|
1,384 lines
(*----------------------------------------------------------------------*)
(* Receive_Xmodem_File --- Download file using XMODEM *)
(*----------------------------------------------------------------------*)
PROCEDURE Receive_Xmodem_File( Use_CRC : BOOLEAN );
(*----------------------------------------------------------------------*)
(* *)
(* Procedure: Receive_Xmodem_File *)
(* *)
(* Purpose: Downloads file from remote host using XMODEM *)
(* protocol. *)
(* *)
(* Calling Sequence: *)
(* *)
(* Receive_Xmodem_File( Use_CRC ); *)
(* *)
(* Use_CRC --- TRUE to use Cyclic redundancy check version *)
(* of XMODEM; FALSE to use Checksum version. *)
(* *)
(* Remarks: *)
(* *)
(* The transmission parameters are automatically set to: *)
(* *)
(* Current baud rate, 8 bits, No parity, 1 stop *)
(* *)
(* and then they are automatically restored to the previous *)
(* values when the transfer is complete. *)
(* *)
(* This code actually controls file reception using any of the *)
(* Xmodem-based protocols: Xmodem, Modem7, Telink, and Ymodem. *)
(* *)
(* Calls: KeyPressed *)
(* Async_Send *)
(* Async_Receive *)
(* Async_Receive_With_Timeout *)
(* Async_Purge_Buffer *)
(* Compute_Crc *)
(* Update_Xmodem_Receive_Display *)
(* Display_Receive_Error *)
(* Receive_Xmodem_Sector *)
(* Receive_Telink_Header *)
(* Receive_Ymodem_Header *)
(* Wait_For_SOH *)
(* Set_File_Date_And_Time *)
(* Draw_Menu_Frame *)
(* Open_Receiving_File *)
(* Write_File_Handle *)
(* Close_File_Handle *)
(* *)
(*----------------------------------------------------------------------*)
CONST
Max_Errors = 20 (* Maximum errors before aborting *)
(* reception *);
VAR
Sector_Count : INTEGER (* Sector count -- no wrap at 255 *);
Sector_Comp : BYTE (* Complement of current sector # *);
Sector_Prev : BYTE (* Previous sector number *);
I : INTEGER (* Loop index *);
Error_Count : INTEGER (* # of errors encountered *);
Ch : INTEGER (* Character read from COM port *);
Error_Flag : BOOLEAN (* IF an error is found *);
Initial_Ch : INTEGER (* Initial character *);
Sector_Length : INTEGER (* Sector Length *);
Sector_Prev1 : BYTE (* Previous sector + 1 *);
BlockL_Errors : INTEGER (* Counts block length errors *);
SOH_Errors : INTEGER (* Counts SOH errors *);
BlockN_Errors : INTEGER (* Counts block number errors *);
Comple_Errors : INTEGER (* Counts complement errors *);
Timeout_Errors: INTEGER (* Counts timeout errors *);
Resend_Errors : INTEGER (* Counts resend block errors *);
CRC_Errors : INTEGER (* Counts checksum/crc errors *);
Effective_Rate: REAL (* Effective baud rate of transfer *);
CRC_Tries : INTEGER (* Initial CRC tries *);
SOH_Time : INTEGER (* Seconds to wait for SOH *);
RFile_Size : REAL (* Actual file size *);
RFile_Date : REAL (* File date/time *);
File_Date : INTEGER (* MS DOS encoded file date *);
File_Time : INTEGER (* MS DOS encoded file time *);
RFile_Name : AnyStr (* Received file name, Ymodem *);
Truncate_File : BOOLEAN (* TRUE to trunc. file to exact size *);
RFile_Open : BOOLEAN (* TRUE if receiving file opened *);
XFile_Byte : FILE OF BYTE (* For truncating received file *);
OK_Transfer : BOOLEAN (* If transfer OK *);
Block_Zero : BOOLEAN (* If block 0 encountered *);
RFile_Size_2 : REAL (* File size from totalling sectors *);
TName : ShortStr (* Transfer type *);
Display_Time : BOOLEAN (* Display time remaining for trans. *);
Time_To_Send : REAL (* Time in seconds to transfer file *);
Start_Time : REAL (* Starting time of transfer *);
End_Time : REAL (* Ending time of transfer *);
Time_Per_Block: REAL (* Time for one block *);
Blocks_To_Get : REAL (* Number of blocks *);
Write_Count : INTEGER (* Number of bytes to write *);
Err : INTEGER (* Error flag for handle I/O *);
(* Write buffer pointer *)
Write_Buffer : File_Handle_Buffer_Ptr;
Buffer_Pos : INTEGER (* Current buffer position *);
Buffer_Length : INTEGER (* Buffer length *);
Use_CRC_2 : BOOLEAN (* TRUE to use CRC method *);
Menu_Title : AnyStr (* Menu title *);
Alt_R_Pressed : BOOLEAN (* TRUE if Alt-R cancelled download *);
Long_Buffer : BOOLEAN (* TRUE if separate buffer used *);
(*----------------------------------------------------------------------*)
(* Open_Receiving_File --- open file to receive download *)
(*----------------------------------------------------------------------*)
PROCEDURE Open_Receiving_File;
VAR
Err: INTEGER;
BEGIN (* Open_Receiving_File *)
(* Check if file name given yet. *)
(* If not, prompt for it. *)
IF FileName = '' THEN
BEGIN
Window( 1, 1, 80, 25 );
GoToXY( 1 , 25 );
WRITE('Enter file name to receive download: ');
READLN( FileName );
END;
(* Open reception file *)
IF ( NOT RFile_Open ) THEN
BEGIN
Err := Create_File_Handle( FileName, Attribute_None, XFile_Handle );
IF ( Err <> 0 ) OR ( Int24Result <> 0 ) THEN
BEGIN
GoToXY( 25 , 10 );
WRITE('Cannot open reception file, download cancelled.');
ClrEol;
DELAY( One_Second_Delay );
Stop_Receive := TRUE;
END
ELSE
RFile_Open := TRUE;
END;
IF Rfile_Open THEN
Writelne('Receiving file ' + FileName, FALSE );
END (* Open_Receiving_File *);
(*----------------------------------------------------------------------*)
(* Initialize_Receive_Display --- Set up display of Xmodem reception *)
(*----------------------------------------------------------------------*)
PROCEDURE Initialize_Receive_Display;
BEGIN (* Initialize_Receive_Display *)
GoToXY( 1 , 1 );
WRITE(' Blocks received :');
ClrEol;
GoToXY( 1 , 2 );
WRITE(' Block length errors :');
ClrEol;
GoToXY( 1 , 3 );
WRITE(' SOH errors :');
ClrEol;
GoToXY( 1 , 4 );
WRITE(' Block number errors :');
ClrEol;
GoToXY( 1 , 5 );
WRITE(' Complement errors :');
ClrEol;
GoToXY( 1 , 6 );
WRITE(' Timeout errors :');
ClrEol;
GoToXY( 1 , 7 );
WRITE(' Resend block errors :');
ClrEol;
GoToXY( 1 , 8 );
IF ( NOT Use_Crc ) THEN
WRITE(' Checksum errors :')
ELSE
WRITE(' CRC errors :');
ClrEol;
GoToXY( 1 , 9 );
IF Display_Time THEN
WRITE(' Approx. time left :')
ELSE
WRITE(' ');
ClrEol;
GoToXY( 1 , 10 );
WRITE (' Last status message :');
ClrEol;
END (* Initialize_Receive_Display *);
(*----------------------------------------------------------------------*)
(* Update_Xmodem_Receive_Display --- Update display of Xmodem reception *)
(*----------------------------------------------------------------------*)
PROCEDURE Update_Xmodem_Receive_Display;
BEGIN (* Update_Xmodem_Receive_Display *)
GoToXY( 25 , 1 );
WRITE( Sector_Count );
GoToXY( 25 , 2 );
WRITE(BlockL_Errors);
GoToXY( 25 , 3 );
WRITE(SOH_Errors);
GoToXY( 25 , 4 );
WRITE(BlockN_Errors);
GoToXY( 25 , 5 );
WRITE(Comple_Errors);
GoToXY( 25 , 6 );
WRITE(Timeout_Errors);
GoToXY( 25 , 7 );
WRITE(Resend_Errors);
GoToXY( 25 , 8 );
WRITE(CRC_Errors);
IF Display_Time THEN
BEGIN
GoToXY( 25 , 9 );
WRITE( TimeString( Time_To_Send ) );
END;
END (* Update_Xmodem_Receive_Display *);
(*----------------------------------------------------------------------*)
(* Display_Receive_Error --- Display XMODEM reception error *)
(*----------------------------------------------------------------------*)
PROCEDURE Display_Receive_Error( Err_Text: AnyStr );
BEGIN (* Display_Receive_Error *)
GoToXY( 25 , 10 );
WRITE(Err_Text,' in block ',Sector_Count);
ClrEol;
Error_Flag := TRUE;
END (* Display_Receive_Error *);
(*----------------------------------------------------------------------*)
(* Receive_Xmodem_Sector --- Get sector using XMODEM *)
(*----------------------------------------------------------------------*)
FUNCTION Receive_Xmodem_Sector( Use_CRC : BOOLEAN ) : BOOLEAN;
(*----------------------------------------------------------------------*)
(* *)
(* Function: Receive_Xmodem_Sector *)
(* *)
(* Purpose: Gets one sector using XMODEM protocol. *)
(* *)
(* Calling Sequence: *)
(* *)
(* OK_Get := Receive_Xmodem_Sector( Use_CRC : BOOLEAN ) *)
(* : BOOLEAN; *)
(* *)
(* Use_CRC --- TRUE to use Cyclic redundancy check version *)
(* of XMODEM; FALSE to use Checksum version. *)
(* OK_Get --- TRUE if sector received correctly *)
(* *)
(* Calls: Async_Send *)
(* Async_Receive_With_Timeout *)
(* Update_Crc *)
(* Display_Receive_Error *)
(* *)
(*----------------------------------------------------------------------*)
VAR
CRC : INTEGER;
Checksum : INTEGER;
I : INTEGER;
BEGIN (* Receive_Xmodem_Sector *)
(* Pick up sector data, calculate *)
(* checksum or CRC *)
Receive_Xmodem_Sector := FALSE;
Checksum := 0;
CRC := 0;
(* Sector length is 128 for usual *)
(* Xmodem or Telink; is 1024 for *)
(* Ymodem. *)
FOR I := 1 TO Sector_Length DO
BEGIN
(* Get next character *)
Async_Receive_With_Timeout( One_Second , Ch );
(* Check for timeout *)
IF Ch = TimeOut THEN
BEGIN
Display_Receive_Error('Block length error');
BlockL_Errors := BlockL_Errors + 1;
END;
(* Store received character *)
Sector_Data[I] := Ch;
(* Update CRC or Checksum *)
IF Use_Crc THEN
CRC := Update_CRC( CRC, Ch )
ELSE
Checksum := ( Checksum + Ch ) AND 255;
END;
(* Now get trailing CRC or *)
(* checksum value. *)
IF Use_Crc THEN
BEGIN (* Receive CRC *)
(* Get first byte of CRC *)
Async_Receive_With_Timeout( One_Second , Ch );
(* Check for timeout *)
IF Ch <> Timeout THEN
BEGIN (* Byte CRC OK *)
(* Update CRC *)
CRC := Update_CRC( CRC , Ch );
(* Get second byte of CRC *)
Async_Receive_With_Timeout( One_Second , Ch );
(* If not timeout, update CRC *)
(* and check if it is zero. *)
(* Zero CRC means OK sector. *)
IF Ch <> Timeout THEN
BEGIN (* Byte 2 CRC OK *)
CRC := Update_CRC( CRC , Ch );
Receive_Xmodem_Sector := ( CRC = 0 );
END (* Byte 2 CRC OK *)
ELSE
BEGIN (* Byte 2 CRC Timeout *)
Display_Receive_Error('Block length error');
BlockL_Errors := BlockL_Errors + 1;
END (* Byte 2 CRC Timeout *)
END (* Byte 1 CRC OK *)
ELSE
BEGIN (* Byte 1 CRC Timeout *)
Display_Receive_Error('Block length error');
BlockL_Errors := BlockL_Errors + 1;
END (* Byte 1 CRC Timeout *);
END (* Compute CRC *)
ELSE
BEGIN (* Receive Checksum *)
(* Read sector checksum, see if it matches *)
(* what we computed from sector read. *)
Async_Receive_With_Timeout( One_Second , Ch );
Receive_Xmodem_Sector := ( Checksum = Ch );
END (* Receive Checksum *);
END (* Receive_Xmodem_Sector *);
(*----------------------------------------------------------------------*)
(* Receive_Telink_Header --- Get Telink block 0 header *)
(*----------------------------------------------------------------------*)
PROCEDURE Receive_Telink_Header;
(*----------------------------------------------------------------------*)
(* *)
(* Procedure: Receive_Telink_Header *)
(* *)
(* Purpose: Gets Telink header block 0 (filename+size+date) *)
(* *)
(* Calling Sequence: *)
(* *)
(* Receive_Telink_Header; *)
(* *)
(* Calls: *)
(* *)
(* Trim *)
(* Dir_Convert_Time *)
(* Dir_Convert_Date *)
(* Draw_Menu_Frame *)
(* *)
(*----------------------------------------------------------------------*)
VAR
I : INTEGER;
CDate : STRING[8];
CTime : STRING[8];
BEGIN (* Receive_Telink_Header *)
RFile_Size := 0.0;
RFile_Name := '';
FOR I := 4 DOWNTO 1 DO
RFile_Size := RFile_Size * 256.0 + Sector_Data[I];
Blocks_To_Get := ROUND( RFile_Size / 128.0 + 0.49 );
File_Time := Sector_Data[6] SHL 8 OR Sector_Data[5];
File_Date := Sector_Data[8] SHL 8 OR Sector_Data[7];
FOR I := 9 TO 24 DO
IF Sector_Data[I] <> 0 THEN
RFile_Name := RFile_Name + CHR( Sector_Data[I] );
RFile_Name := TRIM( Rfile_Name );
Draw_Menu_Frame( 15, 10, 78, 23, Menu_Frame_Color,
Menu_Text_Color,
'Receive file ' + FileName + ' using ' + Tname );
Dir_Convert_Time( File_Time, CTime );
Dir_Convert_Date( File_Date, CDate );
Draw_Menu_Frame( 15, 3, 78, 9, Menu_Frame_Color,
Menu_Text_Color, '' );
(* Headings for Ymodem information *)
Window( 16, 4, 77, 8 );
GoToXY( 1 , 1 );
WRITE(' File name: ',FileName);
GoToXY( 1 , 2 );
WRITE(' File Size in bytes: ',RFile_Size:8:0);
GoToXY( 1 , 3 );
WRITE(' File Size in blocks: ',Blocks_To_Get:8:0);
GoToXY( 1 , 4 );
WRITE(' File creation time: ',CTime );
GoToXY( 1 , 5 );
WRITE(' File creation date: ',CDate );
(* Restore previous window *)
Window( 16, 11, 77, 21 );
IF RFile_Size > 0.0 THEN
BEGIN
Display_Time := TRUE;
Time_To_Send := Blocks_To_Get * ( Trans_Time_Val / Baud_Rate );
Time_Per_Block := Time_To_Send / Blocks_To_Get;
Initialize_Receive_Display;
Truncate_File := TRUE;
END;
(* Prevent clobbers in host mode *)
IF Host_Mode THEN
Stop_Receive := Stop_Receive OR
Scan_Xfer_List( FileName ) OR
( FileName = 'PIBTERM.USF' ) OR
( FileName = 'PIBTERM.XFR' ) OR
( FileName = 'PIBTERM.MSG' ) OR
( FileName = 'PIBTERM.CMT' ) OR
( FileName = 'PIBTERM.CMT' );
END (* Receive_Telink_Header *);
(*----------------------------------------------------------------------*)
(* Receive_Ymodem_Header --- Get Ymodem block 0 header *)
(*----------------------------------------------------------------------*)
PROCEDURE Receive_Ymodem_Header;
(*----------------------------------------------------------------------*)
(* *)
(* Procedure: Receive_Ymodem_Header *)
(* *)
(* Purpose: Gets Ymodem header block 0 (filename+size+date) *)
(* *)
(* Calling Sequence: *)
(* *)
(* Receive_Ymodem_Header *)
(* *)
(* Calls: *)
(* *)
(* Draw_Menu_Frame *)
(* Dir_Convert_Time *)
(* Dir_Convert_Date *)
(* Open_Receiving_File *)
(* *)
(*----------------------------------------------------------------------*)
VAR
I : INTEGER;
CTime : STRING[10];
CDate : STRING[10];
Year : INTEGER;
Month : INTEGER;
Day : INTEGER;
Hour : INTEGER;
Mins : INTEGER;
Secs : INTEGER;
(*----------------------------------------------------------------------*)
PROCEDURE Get_Ymodem_Date( Date : REAL;
VAR Year : INTEGER;
VAR Month : INTEGER;
VAR Day : INTEGER;
VAR Hour : INTEGER;
VAR Mins : INTEGER;
VAR Secs : INTEGER );
CONST
Secs_Per_Year = 31536000.0;
Secs_Per_Leap_Year = 31622400.0;
Secs_Per_Day = 86400.0;
Secs_Per_Hour = 3600.0;
Secs_Per_Minute = 60.0;
VAR
RDate : REAL;
T : REAL;
(* STRUCTURED *) CONST
Days_Per_Month : ARRAY[1..12] OF BYTE
= ( 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 );
BEGIN (* Get_Ymodem_Date *)
Year := 1970;
Month := 1;
RDate := Date - GMT_Difference * Secs_Per_Hour;
WHILE( RDate > 0.0 ) DO
BEGIN
IF ( Year MOD 4 ) = 0 THEN
T := Secs_Per_Leap_Year
ELSE
T := Secs_Per_Year;
RDate := RDate - T;
Year := Year + 1;
END;
RDate := RDate + T;
Year := Year - 1;
IF ( Year MOD 4 ) = 0 THEN
Days_Per_Month[2] := 29
ELSE
Days_Per_Month[2] := 28;
WHILE( RDate > 0.0 ) DO
BEGIN
T := Days_Per_Month[Month] * Secs_Per_Day;
RDate := RDate - T;
Month := Month + 1;
END;
RDate := RDate + T;
Month := Month - 1;
Day := TRUNC( INT( ( Rdate + Secs_Per_Day - 1 ) / Secs_Per_Day ) );
Rdate := Rdate - ( Day - 1 ) * Secs_Per_Day;
Hour := TRUNC( INT( Rdate / Secs_Per_Hour ) );
Rdate := Rdate - Hour * Secs_Per_Hour;
Mins := TRUNC( INT( Rdate / Secs_Per_Minute ) );
Secs := TRUNC( Rdate - Mins * Secs_Per_Minute );
END (* Get_Ymodem_Date *);
(*----------------------------------------------------------------------*)
BEGIN (* Receive_Ymodem_Header *)
RFile_Size := 0.0;
RFile_Date := 0.0;
RFile_Name := '';
File_Time := 0;
File_Date := 0;
(* Pick up file name *)
I := 1;
WHILE( Sector_Data[I] <> NUL ) DO
BEGIN
RFile_Name := RFile_Name + CHR( Sector_Data[I] );
I := I + 1;
END;
(* If null file name, this means *)
(* end of Ymodem batch, so quit. *)
IF LENGTH( RFile_Name ) = 0 THEN
BEGIN
Null_File_Name := TRUE;
EXIT;
END;
(* Pick up file size *)
I := I + 1;
WHILE( Sector_Data[I] <> NUL ) AND ( Sector_Data[I] <> ORD(' ') ) DO
BEGIN
RFile_Size := RFile_Size * 10.0 + ORD( Sector_Data[I] ) - ORD('0');
I := I + 1;
END;
I := I + 1;
WHILE( Sector_Data[I] <> NUL ) AND ( Sector_Data[I] <> ORD(' ') ) DO
BEGIN
RFile_Date := RFile_Date * 8.0 + ORD( Sector_Data[I] ) - ORD('0');
I := I + 1;
END;
IF RFile_Date > 0 THEN
BEGIN
Get_Ymodem_Date( RFile_Date, Year, Month, Day, Hour, Mins, Secs );
File_Time := Hour SHL 11 OR Mins SHL 5 OR ( Secs DIV 2 );
File_Date := MAX( Year - 1980 , 0 ) SHL 9 + Month SHL 5 + Day;
Dir_Convert_Time( File_Time, CTime );
Dir_Convert_Date( File_Date, CDate );
END;
Draw_Menu_Frame( 15, 3, 78, 9, Menu_Frame_Color,
Menu_Text_Color,
'Receive file ' + RFile_Name + ' using ' + Tname );
(* Headings for Ymodem information *)
Window( 16, 4, 77, 8 );
GoToXY( 1 , 1 );
WRITE(' File name: ',RFile_Name);
Blocks_To_Get := ROUND( RFile_Size / 1024.0 + 0.49 );
IF RFile_Size > 0.0 THEN
BEGIN
GoToXY( 1 , 2 );
WRITE(' File Size in bytes: ',RFile_Size:8:0);
GoToXY( 1 , 3 );
WRITE(' File Size in 1K blocks: ',Blocks_To_Get:8:0);
END;
Blocks_To_Get := ROUND( RFile_Size / 128.0 + 0.49 );
IF File_Date > 0 THEN
BEGIN
GoToXY( 1 , 4 );
WRITE(' File creation time: ',CTime );
GoToXY( 1 , 5 );
WRITE(' File creation date: ',CDate );
END;
FileName := RFile_Name;
(* Restore previous window *)
Window( 16, 11, 77, 21 );
IF Rfile_Size > 0.0 THEN
BEGIN
Display_Time := TRUE;
Time_To_Send := Blocks_To_Get * ( Trans_Time_Val / Baud_Rate );
Time_Per_Block := Time_To_Send / Blocks_To_Get;
Initialize_Receive_Display;
Truncate_File := ( RFile_Size > 0.0 );
END;
(* Prevent clobbers in host mode *)
IF Host_Mode THEN
Stop_Receive := Stop_Receive OR
Scan_Xfer_List( FileName ) OR
( FileName = 'PIBTERM.USF' ) OR
( FileName = 'PIBTERM.XFR' ) OR
( FileName = 'PIBTERM.MSG' ) OR
( FileName = 'PIBTERM.CMT' ) OR
( FileName = 'PIBTERM.CMT' );
(* Open reception file *)
IF ( NOT Stop_Receive ) THEN
Open_Receiving_File;
END (* Receive_Ymodem_Header *);
(*----------------------------------------------------------------------*)
(* Wait_For_SOH --- Wait for start for start of XMODEM block *)
(*----------------------------------------------------------------------*)
PROCEDURE Wait_For_SOH( Wait_Time : INTEGER;
VAR Initial_Ch : INTEGER;
VAR Stop_Receive : BOOLEAN );
(*----------------------------------------------------------------------*)
(* *)
(* Procedure: Wait_For_SOH *)
(* *)
(* Purpose: Waits for SOH/STX/SYN initiating Xmodem block *)
(* *)
(* Calling Sequence: *)
(* *)
(* Wait_For_SOH( Wait_Time : INTEGER; *)
(* VAR Initial_Ch : INTEGER; *)
(* VAR Stop_Receive : BOOLEAN ); *)
(* *)
(* Wait_Time --- time to wait for character in seconds *)
(* Initial_Ch --- returned initial character *)
(* Stop_Receive --- TRUE if Alt-R hit to stop transfer *)
(* *)
(* Calls: *)
(* *)
(* Async_Receive_With_Timeout *)
(* *)
(*----------------------------------------------------------------------*)
VAR
Kbd_Ch: CHAR;
ITime : INTEGER;
BEGIN (* Wait_For_SOH *)
(* If already cancelled transfer, *)
(* don't look for more input! *)
Initial_Ch := TimeOut;
IF Stop_Receive THEN EXIT;
(* Look for start of Xmodem block *)
ITime := 0;
REPEAT
ITime := ITime + 1;
Async_Receive_With_Timeout( One_Second, Initial_Ch );
(* Check for keyboard input -- Alt_R *)
(* cancels transfer. *)
IF KeyPressed THEN
BEGIN
READ( Kbd, Kbd_Ch );
IF ( Kbd_Ch = CHR( ESC ) ) AND KeyPressed THEN
BEGIN
READ( Kbd, Kbd_Ch );
Alt_R_Pressed := ( ORD( Kbd_Ch ) = Alt_R );
Stop_Receive := Stop_Receive OR Alt_R_Pressed;
END;
END;
(* Also stop transfer if carrier drops *)
IF Async_Carrier_Drop THEN
BEGIN
Stop_Receive := TRUE;
Initial_Ch := TimeOut;
END;
UNTIL ( Stop_Receive OR
( ITime > Wait_Time ) OR
( Initial_Ch <> TimeOut ) );
END (* Wait_For_SOH *);
(*----------------------------------------------------------------------*)
(* Set_File_Date_And_Time --- set file date and time stamp *)
(*----------------------------------------------------------------------*)
PROCEDURE Set_File_Date_And_Time;
VAR
OLd_Time : INTEGER;
Old_Date : INTEGER;
Err : INTEGER;
File_Handle: INTEGER;
(*----------------------------------------------------------------------*)
PROCEDURE Set_File_Time_Error;
BEGIN (* Set_File_Time_Error *)
GoToXY( 25 , 10 );
WRITE('Could not set date/time for file.');
ClrEol;
DELAY( One_Second_Delay );
END (* Set_File_Time_Error *);
(*----------------------------------------------------------------------*)
BEGIN (* Set_File_Date_And_Time *)
Err := Open_File_Handle( FileName, Access_Read_And_Write_Mode,
File_Handle );
IF ( Err <> 0 ) OR ( Int24Result <> 0 ) THEN
Set_File_Time_Error
ELSE
BEGIN
Err := Dir_Set_File_Date_And_Time( File_Handle, File_Date,
File_Time );
IF ( Err <> 0 ) OR ( Int24Result <> 0 ) THEN
Set_File_Time_Error
ELSE
BEGIN
Err := Close_File_Handle( File_Handle );
IF ( Err <> 0 ) OR ( Int24Result <> 0 ) THEN
Set_File_Time_Error;
END;
END;
END (* Set_File_Date_And_Time *);
(*----------------------------------------------------------------------*)
(* Write_File_Data --- Write received data to file *)
(*----------------------------------------------------------------------*)
PROCEDURE Write_File_Data;
PROCEDURE Do_Actual_Write( Write_Count: INTEGER );
BEGIN (* Do_Actual_Write *)
IF ( ( RFile_Size_2 + Write_Count ) > RFile_Size ) AND Truncate_File THEN
Write_Count := TRUNC( RFile_Size - Rfile_Size_2 );
Err := Write_File_Handle( XFile_Handle, Write_Buffer^, Write_Count );
IF ( Err <> 0 ) OR ( Int24Result <> 0 ) THEN
BEGIN
GoToXY( 25 , 10 );
WRITE('Error in writing to disk, transfer cancelled.');
ClrEol;
DELAY( One_Second_Delay );
Stop_Receive := TRUE;
END;
RFile_Size_2 := RFile_Size_2 + Write_Count;
END (* Do_Actual_Write *);
(*----------------------------------------------------------------------*)
BEGIN (* Write_File_Data *)
(* Write directly from sector *)
(* if not long buffer used *)
IF ( NOT Long_Buffer ) THEN
Do_Actual_Write( Sector_Length )
(* Store sector data in long *)
(* buffer and write file if *)
(* necessary. *)
ELSE
BEGIN
IF ( Buffer_Pos + Sector_Length ) > Buffer_Length THEN
BEGIN
Do_Actual_Write( Buffer_Pos );
Buffer_Pos := 0;
END;
MOVE( Sector_Data, Write_Buffer^[ Buffer_Pos + 1 ], Sector_Length );
Buffer_Pos := Buffer_Pos + Sector_Length;
END;
END (* Write_File_Data *);
(*----------------------------------------------------------------------*)
(* Cancel_Transfer --- Cancel transfer *)
(*----------------------------------------------------------------------*)
PROCEDURE Cancel_Transfer;
BEGIN (* Cancel_Transfer *)
(* Purge reception *)
Async_Purge_Buffer;
(* Send five cancels, then five *)
(* backspaces. *)
Async_Send( CHR( CAN ) );
Async_Send( CHR( CAN ) );
Async_Send( CHR( CAN ) );
Async_Send( CHR( CAN ) );
Async_Send( CHR( CAN ) );
Async_Send( CHR( BS ) );
Async_Send( CHR( BS ) );
Async_Send( CHR( BS ) );
Async_Send( CHR( BS ) );
Async_Send( CHR( BS ) );
END (* Cancel_Transfer *);
(*----------------------------------------------------------------------*)
BEGIN (* Receive_Xmodem_File *)
(* Open display window for transfer *)
Save_Screen( Saved_Screen );
CASE Transfer_Protocol OF
Xmodem_Chk : Tname := 'Xmodem (Checksum)';
Xmodem_Crc : Tname := 'Xmodem (CRC)';
Telink : Tname := 'Telink';
Modem7_Chk : Tname := 'Modem7 (Checksum)';
Modem7_CRC : Tname := 'Modem7 (CRC)';
Ymodem : Tname := 'Ymodem';
Ymodem_Batch : Tname := 'Ymodem Batch';
END (* CASE *);
IF FileName = '' THEN
Menu_Title := 'Receive file using ' + Tname
ELSE
Menu_Title := 'Receive file ' + FileName + ' using ' + Tname;
Draw_Menu_Frame( 15, 10, 78, 22, Menu_Frame_Color,
Menu_Text_Color, Menu_Title );
Window( 16, 11, 77, 21 );
(* Initialize status display information *)
SOH_Errors := 0;
BlockL_Errors := 0;
BlockN_Errors := 0;
Comple_Errors := 0;
Timeout_Errors := 0;
Resend_Errors := 0;
CRC_Errors := 0;
Display_Time := FALSE;
Initialize_Receive_Display;
(* Current sector = 0 *)
Sector_Number := 0;
Sector_Count := 0;
Sector_Prev := 0;
Sector_Length := 128;
(* Overall error count = 0 *)
Error_Count := 0;
(* CRC tries *)
CRC_Tries := 0;
(* How long to wait for SOH *)
SOH_Time := Ten_Seconds;
(* Assume file size not sent *)
Truncate_File := FALSE;
(* Assume file size, date not sent *)
RFile_Size := 0.0;
RFile_Size_2 := 0.0;
RFile_Date := 0.0;
File_Date := 0;
File_Time := 0;
(* Assume file name not sent *)
RFile_Name := '';
(* Assume transfer fails *)
OK_Transfer := FALSE;
(* Assume block 0 not found *)
Block_Zero := FALSE;
(* Starting time *)
Start_Time := TimeOfDay;
(* User intervention flag *)
Alt_R_Pressed := FALSE;
(* Serious error flag *)
Stop_Receive := FALSE;
(* Not null file name *)
Null_File_Name := FALSE;
(* Allocate buffer if requested *)
(* otherwise use sector data area *)
(* directly. *)
IF Max_Write_Buffer > 1024 THEN
BEGIN
Buffer_Length := Max_Write_Buffer;
Long_Buffer := TRUE;
GetMem( Write_Buffer , Buffer_Length );
END
ELSE
BEGIN
Long_Buffer := FALSE;
Write_Buffer := ADDR( Sector_Data );
END;
(* Empty write buffer *)
Buffer_Pos := 0;
(* Open reception file now if possible *)
RFile_Open := FALSE;
IF FileName <> '' THEN
BEGIN
Open_Receiving_File;
IF Stop_Receive THEN
BEGIN
Cancel_Transfer;
DELAY( Two_Second_Delay );
Restore_Screen( Saved_Screen );
Reset_Global_Colors;
EXIT;
END;
END;
(* Begin XMODEM loop *)
REPEAT
(* Reset error flag *)
Error_flag := FALSE;
(* Look for SOH *)
REPEAT
IF Sector_Count = 0 THEN
BEGIN
Use_CRC := Use_CRC AND ( CRC_Tries < 4 );
(* Purge reception *)
Async_Purge_Buffer;
(* Indicate XMODEM type *)
IF Use_Crc THEN
Async_Send( 'C' )
ELSE
Async_Send( CHR( NAK ) );
CRC_Tries := CRC_Tries + 1;
GoToXY( 1 , 8 );
IF ( NOT Use_Crc ) THEN
WRITELN(' Checksum errors :')
ELSE
WRITELN(' CRC errors :');
END;
Wait_For_SOH( SOH_Time, Initial_Ch , Stop_Receive );
(* If CAN found, insist on *)
(* at least two CANs in a row *)
(* before cancelling transfer *)
IF Initial_Ch = CAN THEN
Wait_For_SOH( SOH_Time, Initial_Ch , Stop_Receive );
UNTIL ( Initial_Ch = SOH ) OR
( Initial_Ch = EOT ) OR
( Initial_Ch = CAN ) OR
( Initial_Ch = SYN ) OR
( Initial_Ch = STX ) OR
( Initial_Ch = TimeOut ) OR
( Error_Count > Max_Errors ) OR
( Stop_Receive );
(* Something wrong already -- *)
(* cancel the transfer. *)
IF Stop_Receive THEN
BEGIN
IF NOT Async_Carrier_Detect THEN
BEGIN
Display_Receive_Error('Carrier dropped.');
DELAY( Two_Second_Delay );
END;
END
(* Timed out -- no SOH found *)
ELSE IF Initial_Ch = Timeout THEN
BEGIN
Display_Receive_Error( 'Time out error, no SOH');
Timeout_Errors := Timeout_Errors + 1;
END
(* SYN found -- Telink header *)
(* SOH found -- start of XMODEM block *)
(* STX found -- start of Ymodem block *)
ELSE IF ( Initial_Ch = SOH ) OR
( Initial_Ch = SYN ) OR
( Initial_Ch = STX ) THEN
BEGIN (* SOH found *)
(* Pick up sector number *)
IF Initial_Ch = STX THEN
Sector_Length := 1024
ELSE
Sector_Length := 128;
Async_Receive_With_Timeout( One_Second , Ch );
IF Ch = TimeOut THEN
BEGIN
BlockL_Errors := BlockL_Errors + 1;
Display_Receive_Error('Short block');
END;
Sector_Number := Ch;
(* Complement of sector number *)
Async_Receive_With_Timeout( One_Second , Ch );
IF Ch = TimeOut THEN
BEGIN
BlockL_Errors := BlockL_Errors + 1;
Display_Receive_Error('Short block');
END;
Sector_Comp := Ch;
(* See if they add up properly *)
IF ( ( Sector_Number + Sector_Comp ) = 255 ) THEN
BEGIN (* Sector number and complement match *)
Sector_Prev1 := Sector_Prev + 1;
Block_Zero := ( Sector_Count = 0 ) AND
( Sector_Number = 0 ) AND
( ( Initial_Ch = SYN ) OR
( Transfer_Protocol IN [Ymodem,
Ymodem_Batch] ) );
IF ( Sector_Number = Sector_Prev1 ) OR Block_Zero THEN
BEGIN (* Correct sector found *)
Use_CRC_2 := Use_CRC AND
( NOT ( Block_Zero AND
( Transfer_Protocol = Telink ) ) );
IF Receive_Xmodem_Sector( Use_CRC_2 ) THEN
IF ( NOT Block_Zero ) THEN
BEGIN (* Checksum/CRC OK *)
Write_File_Data;
Error_Count := 0;
Sector_Count := Sector_Count + 1;
Sector_Prev := Sector_Number;
Async_Send( CHR( ACK ) );
END (* Checksum/CRC OK *)
ELSE (* Telink/Ymodem block 0 *)
BEGIN
IF ( Initial_Ch = SYN ) THEN
Receive_Telink_Header
ELSE IF ( Transfer_Protocol IN [Ymodem,
Ymodem_Batch] ) THEN
Receive_Ymodem_Header;
IF ( NOT Stop_Receive ) THEN
BEGIN
Async_Send( CHR( ACK ) );
Error_Count := 0;
END;
END
ELSE
BEGIN (* Checksum/CRC error *)
CRC_Errors := CRC_Errors + 1;
IF Use_Crc THEN
Display_Receive_Error('CRC error')
ELSE
Display_Receive_Error('Checksum error');
END (* Checksum/CRC error *)
END (* Correct sector found *)
ELSE
IF ( Sector_Number = Sector_Prev ) THEN
BEGIN (* Duplicate sector *)
Display_Receive_Error('Duplicate block ');
Resend_Errors := Resend_Errors + 1;
Async_Send( CHR( ACK ) );
END (* Duplicate sector *)
ELSE
BEGIN
Display_Receive_Error('Synchronization error');
BlockN_Errors := BlockN_Errors + 1;
END;
END (* Sector # and complement match *)
ELSE
BEGIN (* Sector # and complement do not match *)
Display_Receive_Error('Sector number error');
Comple_Errors := Comple_Errors + 1;
END (* Sector # and complement do not match *);
END (* SOH Found *)
ELSE IF ( Initial_Ch <> EOT ) THEN
BEGIN
Display_Receive_Error('SOH not found');
SOH_Errors := SOH_Errors + 1;
END;
IF Error_Flag THEN
BEGIN
Error_Count := Error_Count + 1;
Async_Purge_Buffer;
Async_Send( CHR( NAK ) );
END;
IF Display_Time THEN
BEGIN
IF ( NOT Error_Flag ) THEN
Time_To_Send := Time_To_Send -
Time_Per_Block * ( Sector_Length / 128 );
IF Time_To_Send < 0.0 THEN
Time_To_Send := 0.0;
END;
Update_Xmodem_Receive_Display;
UNTIL ( Initial_Ch = EOT ) OR
( Initial_Ch = CAN ) OR
( Stop_Receive ) OR
( Null_File_Name ) OR
( Error_Count > Max_Errors );
(* If serious error or Alt_R hit, *)
(* stop download. *)
IF ( Stop_Receive ) THEN
BEGIN
Cancel_Transfer;
IF Alt_R_Pressed THEN
BEGIN
GoToXY( 25 , 10 );
WRITE('Alt-R key hit -- reception cancelled.');
Writelne('ALT-R key hit, reception cancelled.', FALSE);
ClrEol;
END;
END
(* Null file name -- end of batch *)
ELSE IF Null_File_Name THEN
BEGIN
GoToXY( 25 , 10 );
WRITE('Null file name received.');
Writelne('Null file name received.', FALSE);
ClrEol;
END
(* EOT received, error count OK *)
ELSE IF ( Initial_Ch = EOT ) AND ( Error_Count <= Max_Errors ) THEN
BEGIN
(* Acknowledge EOT *)
Async_Send( CHR( ACK ) );
(* Write any remaining data in buffer *)
IF Buffer_Pos > 0 THEN
BEGIN
Write_Count := Buffer_Pos;
IF ( ( RFile_Size_2 + Write_Count ) > RFile_Size ) AND
Truncate_File THEN
Write_Count := TRUNC( RFile_Size - Rfile_Size_2 );
Err := Write_File_Handle( XFile_Handle, Write_Buffer^, Write_Count );
IF ( Err <> 0 ) OR ( Int24Result <> 0 ) THEN
BEGIN
GoToXY( 25 , 10 );
WRITE('Error in writing to disk, file may be bad.');
ClrEol;
DELAY( One_Second_Delay );
END;
RFile_Size_2 := RFile_Size_2 + Write_Count;
END;
GoToXY( 2 , 10 );
WRITE('Transfer complete; ');
End_Time := TimeOfDay;
IF RFile_Size > 0.0 THEN
IF RFile_Size <= RFile_Size_2 THEN
RFile_Size_2 := RFile_Size;
IF End_Time > Start_Time THEN
BEGIN
Effective_Rate := RFile_Size_2 / ( End_Time - Start_Time );
WRITE('transfer rate was ',Effective_Rate:6:1,' CPS');
ClrEol;
OK_Transfer := TRUE;
END;
Writelne('Received file ' + FileName , FALSE );
END
ELSE IF ( Initial_Ch = CAN ) THEN
BEGIN
GoToXY( 25 , 10 );
WRITE('Transmitter cancelled file transfer.');
Writelne('Transmitter cancelled file transfer.', FALSE);
ClrEol;
END
ELSE
BEGIN
GoToXY( 25 , 10 );
WRITE('Transfer Cancelled');
Writelne('Transfer cancelled', FALSE);
ClrEol;
END;
(* Close transferred file *)
Err := Close_File_Handle( XFile_Handle );
I := Int24Result;
(* Set file time and date if Telink *)
(* or Ymodem *)
IF ( File_Date > 0 ) AND Use_Time_Sent THEN
Set_File_Date_And_Time;
DELAY( Two_Second_Delay );
(* Remove download buffer *)
IF Long_Buffer THEN
FREEMEM( Write_Buffer , Buffer_Length );
(* Remove XMODEM window *)
Restore_Screen( Saved_Screen );
Reset_Global_Colors;
END (* Receive_Xmodem_File *) ;